//
//  main.m
//  OC08_iOS9新特性(Nullability, 泛型, _kindof)
//
//  Created by Hanlingyu on 16/7/13.
//  Copyright © 2016年 ltq. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Truck.h"
#import "Student.h"
int main(int argc, const char * argv[]) {
#pragma mark - 1. nullability
    // nonnull 修饰的属性 对应的getter和setter方法
    Person *per = [[Person alloc] init];
    NSString *objc = nil;
//    per.name = nil;
    [per setName:objc];
//    [per setName:<#(NSString * _Nonnull)#>];
    per.name = @"张三";
    
    
    // nullable 修饰的属性, 对应的getter和setter方法
//    [per setSex:<#(NSString * _Nullable)#>];
//    [per sex];
    per.sex = nil;
    
    
    // null_resettable
//    [[per setFriends:<#(NSArray * _Nullable)#>];
//     [per friends];
    
//    per setDic:(NSDictionary * _Nonnull)
    
    
#pragma mark - 2. 泛型
    // 带泛型的容器 (规定了容器中所存储的类型)
    // 声明一个可变数组, 内部存放的都是NSString
    // 1. 数组中添加其他类型, 会有警告
    // 2. 数组取出来的类型不在是id类型, 对应变成声明时的类型
    // 3. 泛型会改变类的一些方法, 使与声明的类型相同
    NSMutableArray<NSString *> *array = [NSMutableArray arrayWithObjects:@"123", nil];
    [array.firstObject length];
    NSString *string = [array firstObject];
    [array addObject:@""];
//    [array addObject:@20];
//    [array addObject:per];
    NSMutableArray *array1 = [NSMutableArray array];
//    [array1 addObject:<#(nonnull id)#>];
//    [array addObject:<#(nonnull NSString *)#>];
    
    NSInteger interger = [array objectAtIndex:0].length;
    
    // 带泛型的字典
    NSMutableDictionary<NSString *, NSString *> *dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"雨涵", @"name", nil];
    [dic objectForKey:@"name"].length;
//    [dic setObject:<#(nonnull NSString *)#> forKey:<#(nonnull id<NSCopying>)#>];
    
#pragma mark - 3. 自定义泛型
    
    Truck<Person *> *truckPer = [[Truck alloc] init];
    
    Student *stu = [[Student alloc] init];
    stu.stuNumber = @"0001";
    [truckPer addObject:stu];
    [truckPer addObject:per];
    [truckPer firstObject];
    
    Truck<Student *> *truckStu = [[Truck alloc] init];
    [truckStu addObject:stu];
    [truckStu addObject:per];
    
#pragma mark - 协变性 与 逆变性
    
    
    Truck *truck = nil;
    Truck<NSArray *> *truck1 = nil;
    Truck<NSMutableArray *> *truck2 = nil;
    
    // 大类型(任意类型) 可以给有泛型的赋值
    // 也可以有泛型的给它赋值
    truck = truck1;
    truck = truck2;
    truck1 = truck;
    truck2 = truck;
    
    // __covariant 协变性 子类在给父类赋值时, 自动强转
    // Truck<NSArray *> 与 Truck<NSMutableArray *>
    truck1 = truck2;
    // __contravariant 逆变性 父类给子类赋值, 自动强转(暂时不知道应用何处)
    truck2 = truck1;
    
#pragma mark - __kindof
    // 加__kindOf修饰后, 返回类型及其子类型, 避免了不必要的强转, 都可以接收这个返回值
    Truck *truckKindOf = [[Truck alloc] init];
    NSArray *arr = [truck returnArray];
    NSMutableArray *a = [truck returnArray];
    
    
    return 0;
}
